//
//  CCMatrix2.cpp
//  ShadowMapping
//
//  Created by Daniel Corleone on 17/6/14.
//  Copyright (c) 2014年 iCloverStudio. All rights reserved.
//

#ifndef __CC_MATRIX2_CPP__
#define __CC_MATRIX2_CPP__

#include "CCMatrixs.h"

template<typename T>
Matrix2<T>::Matrix2()
: m00(0), m01(0)
, m10(0), m11(0)
{}

template<typename T>
Matrix2<T>::Matrix2(const T src[4])
: m00(src[0]), m01(src[1])
, m10(src[2]), m11(src[3])
{}

template<typename T>
Matrix2<T>::Matrix2(T xx, T xy, T yx, T yy)
: m00(xx), m01(xy)
, m10(yx), m11(yy)
{}

template<typename T>
Matrix2<T>::Matrix2(const Matrix2<T>& other)
: m00(other[0]), m01(other[1])
, m10(other[2]), m11(other[3])
{}

template<typename T>
void
Matrix2<T>::set(const T src[4]) {
    m[0] = src[0]; m[1] = src[1]; m[2] = src[2]; m[3] = src[3];
    return;
}

template<typename T>
void
Matrix2<T>::set(T xx, T xy, T yx, T yy) {
    m[0] = xx; m[1] = xy; m[2] = yx; m[3] = yy;
    return;
}

template<typename T>
void
Matrix2<T>::setRow(Int32 index, const T row[2])
{
    m[index * 2] = row[0];
    m[index * 2 + 1] = row[1];
    return;
}

template<typename T>
void
Matrix2<T>::setRow(Int32 index, const Vector2<T> &v) {
    m[index * 2] = v.x;
    m[index * 2 + 1] = v.y;
    return;
}

template<typename T>
void
Matrix2<T>::setColumn(Int32 index, const T *col) {
    m[index] = col[0];
    m[index+2] = col[1];
    return;
}

template<typename T>
void
Matrix2<T>::setColumn(Int32 index, const Vector2<T> &v)
{
    m[index] = v.x;
    m[index + 2] = v.y;
    return;
}

template<typename T>
const T*
Matrix2<T>::get() const {
    return m;
}

template<typename T>
Real
Matrix2<T>::getDeterminant()
{
    return m[0] * m[3] - m[1] * m[2];
}

template<typename T>
Matrix2<T>&
Matrix2<T>::identity()
{
    m[0] = m[3] = 1.0;
    m[1] = m[2] = 0.0;
    return *this;
}

template<typename T>
Matrix2<T>&
Matrix2<T>::invert()
{
    Real determinant = getDeterminant();
    if (::fabs(determinant) <= FLOAT_MIN) {
        return identity();
    }
    
    T tmp = m[0];   // copy the first element
    Real invDeterminant = 1.0 / determinant;
    m[0] =  invDeterminant * m[3];
    m[1] = -invDeterminant * m[1];
    m[2] = -invDeterminant * m[2];
    m[3] =  invDeterminant * tmp;
    
    return *this;
}

template<typename T>
Matrix2<T>&
Matrix2<T>::transpose()
{
    std::swap(m[1], m[2]);
    return *this;
}


template<typename T>
Matrix2<T>
Matrix2<T>::operator+(const Matrix2<T>& other) const {
    return Matrix2<T>(m[0] + other[0], m[1] + other[1],
                      m[2] + other[2], m[3] + other[3]);
}

template<typename T>
Matrix2<T>
Matrix2<T>::operator-(const Matrix2<T>& other) const {
    return Matrix2<T>(m[0] - other[0], m[1] - other[1],
                      m[2] - other[2], m[3] - other[3]);
}

template<typename T>
Matrix2<T>&
Matrix2<T>::operator+=(const Matrix2<T>& other) {
    m[0] += other[0]; m[1] += other[1];
    m[2] += other[2]; m[3] += other[3];
    return *this;
}

template<typename T>
Matrix2<T>&
Matrix2<T>::operator-=(const Matrix2<T>& other) {
    m[0] -= other[0]; m[1] -= other[1];
    m[2] -= other[2]; m[3] -= other[3];
    return *this;
}

template<typename T>
Vector2<T>
Matrix2<T>::operator*(const Vector2<T>& v) const {
    return Vector2<T>(m[0]*v.x + m[1]*v.y, m[2]*v.x + m[3]*v.y);
}

template<typename T>
Matrix2<T>
Matrix2<T>::operator*(const Matrix2<T>& rhs) const {
    return Matrix2<T>(m[0]*rhs[0] + m[1]*rhs[2],  m[0]*rhs[1] + m[1]*rhs[3],
                      m[2]*rhs[0] + m[3]*rhs[2],  m[2]*rhs[1] + m[3]*rhs[3]);
}

template<typename T>
Matrix2<T>&
Matrix2<T>::operator*=(const Matrix2<T>& rhs) {
    *this = *this * rhs;
    return *this;
}

template<typename T>
Boolean
Matrix2<T>::operator==(const Matrix2<T>& other) const {
    return (m[0] == other[0] && m[1] == other[1] &&
            m[2] == other[2] && m[3] == other[3]);
}

template<typename T>
Boolean
Matrix2<T>::operator!=(const Matrix2<value_type> &rhs) const {
    return !(*this == rhs);
}

template<typename T>
T
Matrix2<T>::operator[](Int32 index) const {
    return m[index];
}

template<typename T>
T&
Matrix2<T>::operator[](Int32 index) {
    return m[index];
}

template<typename T>
Matrix2<T>
Matrix2<T>::operator-() const {
    return Matrix2<T>(-m[0], -m[1],
                      -m[2], -m[3]);
}

template<typename T>
Matrix2<T>
Matrix2<T>::operator*(Real s) const {
    return Matrix2<T>(m[0]*s, m[1]*s,
                      m[2]*s, m[3]*s);
}

template<typename T>
Matrix2<T>&
Matrix2<T>::operator*=(Real s) {
    m[0] *= s; m[1] *= s;
    m[2] *= s; m[3] *= s;
    return *this;
}


#endif  /// __CC_MATRIX2_CPP__
